#include "mainwindow.h"

#include <QApplication>
#include <QScreen>
#include <QFont>
#include <QPainter>
#include <QDebug>
#include <QGuiApplication>
#include <QWindow>
#include <QJsonDocument>
#include <QJsonObject>
#include <QVBoxLayout>
#include <QtWidgets>


/**
 * @brief MainWindow类的构造函数。
 * 
 * 此构造函数用于初始化MainWindow对象，执行以下操作：
 * 1. 初始化成员变量，如标签、定时器、套接字服务器等。
 * 2. 获取所有屏幕的信息。
 * 3. 初始化用户界面。
 * 4. 初始化Unix Domain Socket服务器。
 * 5. 根据提供的屏幕名称尝试将窗口移动到指定屏幕，若名称无效则显示错误信息并移动到最高索引的屏幕。
 * 6. 连接定时器信号到相应的槽函数，用于启动屏幕捕获和定期屏幕捕获。
 * 
 * @param screenName 要移动到的屏幕的名称，若为空则使用最高索引的屏幕。
 * @param parent 父窗口指针，默认为nullptr。
 */
MainWindow::MainWindow(const QString &screenName, QWidget *parent)
    : QMainWindow(parent)
    // 初始化中央标签，用于显示信息或屏幕截图
    , m_centralLabel(new QLabel(this))
    // 初始化启动屏幕捕获的定时器
    , m_startCaptureTimer(new QTimer(this))
    // 初始化屏幕捕获定时器，用于定期捕获屏幕
    , m_captureTimer(new QTimer(this))
    // 初始化最低屏幕索引为0
    , m_lowestScreenIndex(0)
    // 初始化最高屏幕索引为0
    , m_highestScreenIndex(0)
    // 初始化Unix Domain Socket服务器
    , m_socketServer(new QLocalServer(this))
    // 初始化当前活动的套接字连接指针为nullptr
    , m_currentSocket(nullptr)
    // 初始化投屏状态为未投屏
    , m_isCasting(false)
    // 初始化正在投屏的屏幕索引为 -1，表示没有选中的投屏屏幕
    , m_castingScreenIndex(-1)
    // 初始化正在投屏的屏幕名称为空字符串
    , m_castingScreenName("")
{
    // 设置窗口标志，使其不在任务栏显示
    setWindowFlags(windowFlags() | Qt::Tool);

    // 获取所有屏幕的信息，并找出最低和最高索引的屏幕
    getScreenInfo();
    
    // 初始化用户界面，设置中央标签的文本、字体和样式
    initializeUI();
    
    // 初始化Unix Domain Socket服务器，设置服务器名称，启动监听连接
    initializeSocketServer();
    
    // 如果提供了屏幕名称，尝试将窗口移动到指定屏幕
    if (!screenName.isEmpty()) {
        // 尝试将窗口移动到指定名称的屏幕
        if (!moveToScreenByName(screenName)) {
            // 如果屏幕名称无效，显示错误信息
            showInvalidScreenNameError(screenName);
            
            // 若指定屏幕无效，将窗口移动到最高索引的屏幕
            moveToHighestIndexScreen();
        }
    } else {
        // 若未提供屏幕名称，将窗口移动到最高索引的屏幕
        moveToHighestIndexScreen();
    }
    
    // 连接启动屏幕捕获定时器的超时信号到 startScreenCapture 槽函数
    connect(m_startCaptureTimer, &QTimer::timeout, this, &MainWindow::startScreenCapture);
    // 设置启动屏幕捕获定时器为单次触发
    m_startCaptureTimer->setSingleShot(true);
    // 此时不启动捕获定时器，将在需要时启动
    
    // 连接屏幕捕获定时器的超时信号到 captureScreen 槽函数，用于定期捕获屏幕
    connect(m_captureTimer, &QTimer::timeout, this, &MainWindow::captureScreen);
}

/**
 * @brief 析构函数，用于释放资源和清理操作。
 * 
 * 此析构函数在 MainWindow 对象销毁时被调用，负责停止所有活动的定时器，
 * 关闭并释放本地套接字服务器和当前活动的套接字连接，以确保资源的正确释放。
 */
MainWindow::~MainWindow()
{
    // 停止启动屏幕捕获的定时器，避免在对象销毁后继续触发
    m_startCaptureTimer->stop();
    // 停止屏幕捕获定时器，确保不再进行屏幕捕获操作
    m_captureTimer->stop();
    
    // 检查本地套接字服务器是否存在
    if (m_socketServer) {
        // 若存在，关闭服务器，停止监听新的连接
        m_socketServer->close();
    }
    
    // 检查当前活动的套接字连接是否存在
    if (m_currentSocket) {
        // 若存在，关闭该套接字连接，终止数据传输
        m_currentSocket->close();
    }
}
/**
 * @brief 根据屏幕名称将窗口移动到指定屏幕并全屏显示。
 * 
 * 此函数尝试在可用屏幕列表中查找具有指定名称的屏幕。
 * 如果找到匹配的屏幕，将窗口移动到该屏幕并设置为全屏显示。
 * 如果未找到匹配的屏幕，则返回 false。
 * 
 * @param screenName 要移动到的屏幕的名称。
 * @return 如果成功找到并移动到指定屏幕，则返回 true；否则返回 false。
 */
bool MainWindow::moveToScreenByName(const QString &screenName)
{
    // 输出调试信息，显示正在尝试移动到指定名称的屏幕
    qDebug() << "Trying to move to screen with name:" << screenName;
    
    // 遍历所有可用屏幕，查找指定名称的屏幕
    for (int i = 0; i < m_screens.size(); ++i) {
        // 获取当前索引对应的屏幕对象
        QScreen *screen = m_screens.at(i);
        
        // 检查当前屏幕的名称是否与指定名称相同
        if (screen->name() == screenName) {
            // 输出调试信息，显示已找到指定名称的屏幕及其索引
            qDebug() << "Found screen with name:" << screenName << "at index:" << i;
            
            // 获取目标屏幕的几何信息（位置和大小）
            QRect screenGeometry = screen->geometry();
            // 将窗口移动到目标屏幕的左上角位置
            move(screenGeometry.x(), screenGeometry.y());
            
            // 将窗口设置为全屏显示
            showFullScreen();
            
            // 找到并移动成功，返回 true
            return true;
        }
    }
    
    // 输出调试信息，显示未找到指定名称的屏幕
    qDebug() << "Screen with name:" << screenName << "not found";
    // 未找到指定屏幕，返回 false
    return false;
}

/**
 * @brief 显示无效屏幕名称的错误信息。
 * 
 * 此函数用于在用户提供的屏幕名称无效时，在界面上显示错误信息。
 * 它会将错误信息设置到中央标签上，并调整字体大小和颜色，最后将文本居中显示。
 * 
 * @param screenName 无效的屏幕名称。
 */
void MainWindow::showInvalidScreenNameError(const QString &screenName)
{
    // 输出调试信息，显示无效的屏幕名称
    qDebug() << "Invalid screen name:" << screenName;
    
    // 设置中央标签的文本为错误信息，包含无效的屏幕名称
    m_centralLabel->setText(QString("无效的屏幕名称: %1").arg(screenName));
    
    // 获取中央标签当前的字体
    QFont font = m_centralLabel->font();
    // 设置字体大小为30
    font.setPointSize(30);
    // 将修改后的字体应用到中央标签
    m_centralLabel->setFont(font);
    // 设置中央标签的样式表，将文本颜色设置为红色
    m_centralLabel->setStyleSheet("color: #FF0000;"); // Red color
    
    // 将中央标签的文本居中显示
    m_centralLabel->setAlignment(Qt::AlignCenter);
}

/**
 * @brief 初始化Unix Domain Socket服务器。
 * 
 * 此函数负责初始化本地套接字服务器，设置服务器名称，移除同名的现有服务器，
 * 启动服务器监听连接，并连接新连接信号到相应的槽函数。
 */
void MainWindow::initializeSocketServer()
{
    // 输出调试信息，表明正在初始化Unix Domain Socket服务器
    qDebug() << "Initializing Unix Domain Socket server";
    
    // 设置服务器名称，用于标识本地套接字服务器
    const QString serverName = "ZhilinWhiteboardSocketServer";
    
    // 移除任何具有相同名称的现有服务器，确保服务器可以正常启动
    QLocalServer::removeServer(serverName);
    
    // 启动服务器，开始监听指定名称的本地套接字连接
    if (!m_socketServer->listen(serverName)) {
        // 如果启动失败，输出错误信息
        qDebug() << "Failed to start Unix Domain Socket server:" << m_socketServer->errorString();
        // 函数返回，不再继续后续操作
        return;
    }
    
    // 输出调试信息，表明服务器已成功启动，并显示监听的服务器名称
    qDebug() << "Unix Domain Socket server started, listening on:" << serverName;
    
    // 连接服务器的 newConnection 信号到 handleNewConnection 槽函数，用于处理新的套接字连接
    connect(m_socketServer, &QLocalServer::newConnection, this, &MainWindow::handleNewConnection);
}

/**
 * @brief 处理新的套接字连接。
 * 
 * 此函数在本地套接字服务器接收到新的连接时被调用。它会获取新的套接字，
 * 如果已有连接则关闭旧连接，存储新的套接字，并连接相应的信号槽以处理数据和断开连接。
 */
void MainWindow::handleNewConnection()
{
    // 输出调试信息，表明接收到了新的套接字连接
    qDebug() << "New socket connection received";
    
    // 从本地套接字服务器获取下一个待处理的连接套接字
    QLocalSocket *socket = m_socketServer->nextPendingConnection();
    
    // 检查是否有可用的待处理连接
    if (!socket) {
        // 若没有，输出调试信息并返回
        qDebug() << "No pending connection";
        return;
    }
    
    // 检查是否已经存在一个活动的套接字连接
    if (m_currentSocket) {
        // 若存在，关闭当前活动的套接字连接
        m_currentSocket->close();
        // 标记当前活动的套接字为待删除，以便在事件循环的下一次迭代中删除
        m_currentSocket->deleteLater();
    }
    
    // 将新的套接字存储为当前活动的套接字
    m_currentSocket = socket;
    
    // 连接套接字的 readyRead 信号到 handleSocketData 槽函数，用于处理接收到的数据
    connect(socket, &QLocalSocket::readyRead, this, &MainWindow::handleSocketData);
    
    // 连接套接字的 disconnected 信号到一个 lambda 函数，用于处理套接字断开连接的情况
    connect(socket, &QLocalSocket::disconnected, [this, socket]() {
        // 输出调试信息，表明套接字已断开连接
        qDebug() << "Socket disconnected";
        
        // 检查断开连接的套接字是否为当前活动的套接字
        if (socket == m_currentSocket) {
            // 若是，将当前活动的套接字指针置为 nullptr
            m_currentSocket = nullptr;
        }
        
        // 标记断开连接的套接字为待删除，以便在事件循环的下一次迭代中删除
        socket->deleteLater();
    });
}

/**
 * @brief 处理从本地套接字接收到的数据。
 * 
 * 此函数在本地套接字接收到数据时被调用。它会读取套接字中的数据，
 * 尝试将其解析为JSON对象，然后调用 handleCommand 函数来处理该命令。
 */
void MainWindow::handleSocketData()
{
    // 输出调试信息，表明接收到了套接字数据
    qDebug() << "Socket data received";
    
    // 获取发送数据的套接字对象
    QLocalSocket *socket = qobject_cast<QLocalSocket*>(sender());
    
    // 检查套接字是否有效
    if (!socket) {
        // 若无效，输出调试信息并返回
        qDebug() << "Invalid socket";
        return;
    }
    
    // 从套接字中读取所有数据
    QByteArray data = socket->readAll();
    
    // 输出接收到的数据内容
    qDebug() << "Received data:" << data;
    
    // 尝试将接收到的字节数组解析为JSON文档
    QJsonDocument doc = QJsonDocument::fromJson(data);
    
    // 检查JSON文档是否为空或不是一个有效的JSON对象
    if (doc.isNull() || !doc.isObject()) {
        // 若无效，输出调试信息并返回
        qDebug() << "Invalid JSON data";
        return;
    }
    
    // 从JSON文档中获取JSON对象
    QJsonObject obj = doc.object();
    
    // 调用 handleCommand 函数处理JSON对象表示的命令
    handleCommand(obj);
}

/**
 * @brief 处理从套接字接收到的命令。
 * 
 * 此函数根据接收到的JSON命令对象中的命令类型执行相应的操作。
 * 支持的命令类型包括 "start-cast"、"stop-cast" 和 "quit-app"。
 * 
 * @param command 包含命令信息的JSON对象。
 */
void MainWindow::handleCommand(const QJsonObject &command)
{
    // 输出调试信息，显示正在处理的命令
    qDebug() << "Handling command:" << command;

    // 从JSON对象中获取命令类型
    QString commandType = command.value("command").toString();

    // 检查命令类型是否为空
    if (commandType.isEmpty()) {
        // 如果为空，输出调试信息并返回
        qDebug() << "Invalid command type";
        return;
    }

    // 根据命令类型执行相应的操作
    if (commandType == "start-cast") {
        // 获取要投屏的屏幕名称
        QString screenName = command.value("name").toString();

        // 检查屏幕名称是否为空
        if (screenName.isEmpty()) {
            // 如果为空，输出调试信息并返回
            qDebug() << "Invalid screen name for start-cast command";
            return;
        }

        // 调用 startCast 函数开始对指定屏幕进行投屏
        startCast(screenName);
    } else if (commandType == "stop-cast") {
        // 调用 stopCast 函数停止当前的屏幕投屏操作
        stopCast();
    } else if (commandType == "quit-app") {
        // 输出调试信息，表明正在退出应用程序
        qDebug() << "Quitting application";
        // 调用 QApplication::quit 函数退出应用程序
        QApplication::quit();
    } else {
        // 如果命令类型未知，输出调试信息
        qDebug() << "Unknown command type:" << commandType;
    }
}

/**
 * @brief 开始对指定屏幕进行投屏。
 * 
 * 此函数用于启动对指定名称屏幕的投屏操作，执行以下操作：
 * 1. 查找指定名称的屏幕。
 * 2. 如果找到屏幕，记录投屏信息。
 * 3. 启动屏幕捕获定时器，开始进行屏幕捕获。
 * 
 * @param screenName 要投屏的屏幕名称。
 */
void MainWindow::startCast(const QString &screenName)
{
    // 输出调试信息，表明正在尝试对指定屏幕进行投屏
    qDebug() << "Starting cast for screen:" << screenName;
    
    // 初始化屏幕索引为 -1，表示未找到指定屏幕
    int screenIndex = -1;
    
    // 遍历所有屏幕，查找指定名称的屏幕
    for (int i = 0; i < m_screens.size(); ++i) {
        // 获取当前索引对应的屏幕对象
        QScreen *screen = m_screens.at(i);
        
        // 检查当前屏幕的名称是否与指定名称相同
        if (screen->name() == screenName) {
            // 如果相同，记录屏幕索引
            screenIndex = i;
            // 找到屏幕后，跳出循环
            break;
        }
    }
    
    // 如果未找到指定名称的屏幕
    if (screenIndex == -1) {
        // 输出调试信息，提示未找到指定屏幕
        qDebug() << "Screen with name:" << screenName << "not found";
        // 函数返回，不进行投屏操作
        return;
    }
    
    // 记录当前正在进行投屏操作
    m_isCasting = true;
    // 记录正在投屏的屏幕索引
    m_castingScreenIndex = screenIndex;
    // 记录正在投屏的屏幕名称
    m_castingScreenName = screenName;
    
    // 启动屏幕捕获定时器，开始进行屏幕捕获，设置短延迟后立即开始
    m_startCaptureTimer->start(100); // Start immediately with a short delay
}

/**
 * @brief 停止屏幕投屏。
 * 
 * 此函数用于停止当前的屏幕投屏操作，执行以下操作：
 * 1. 停止屏幕捕获定时器。
 * 2. 重置投屏相关的信息。
 * 3. 恢复UI到初始状态。
 */
void MainWindow::stopCast()
{
    // 输出调试信息，表明正在停止投屏
    qDebug() << "Stopping cast";
    
    // 停止屏幕捕获定时器，不再进行屏幕捕获
    m_captureTimer->stop();
    
    // 重置投屏状态为未投屏
    m_isCasting = false;
    // 重置正在投屏的屏幕索引为 -1，表示没有选中的投屏屏幕
    m_castingScreenIndex = -1;
    // 重置正在投屏的屏幕名称为空字符串
    m_castingScreenName = "";
    
    // 恢复UI到初始状态，显示初始的界面信息
    initializeUI();
}
/**
 * @brief 获取所有屏幕的信息，并找出最低和最高索引的屏幕。
 * 
 * 此函数首先获取所有可用的屏幕，然后遍历这些屏幕，输出每个屏幕的详细信息，
 * 包括名称、几何信息、物理尺寸、DPI和刷新率。同时，它会记录最低和最高索引的屏幕。
 */
void MainWindow::getScreenInfo()
{
    // 获取所有可用的屏幕
    m_screens = QGuiApplication::screens();
    
    // 输出屏幕的数量
    qDebug() << "Number of screens: " << m_screens.size();
    
    // 初始化最低屏幕索引为0
    m_lowestScreenIndex = 0;
    // 初始化最高屏幕索引为0
    m_highestScreenIndex = 0;
    
    // 遍历所有屏幕
    for (int i = 0; i < m_screens.size(); ++i) {
        // 获取当前索引对应的屏幕对象
        QScreen *screen = m_screens.at(i);
        
        // 输出当前屏幕的索引信息
        qDebug() << "Screen" << i << ":";
        // 输出当前屏幕的名称
        qDebug() << "  Name:" << screen->name();
        // 输出当前屏幕的几何信息（位置和大小）
        qDebug() << "  Geometry:" << screen->geometry();
        // 输出当前屏幕的物理尺寸（毫米）
        qDebug() << "  Physical size:" << screen->physicalSize() << "mm";
        // 输出当前屏幕的逻辑每英寸点数（DPI）
        qDebug() << "  Logical DPI:" << screen->logicalDotsPerInch();
        // 输出当前屏幕的物理每英寸点数（DPI）
        qDebug() << "  Physical DPI:" << screen->physicalDotsPerInch();
        // 输出当前屏幕的刷新率（Hz）
        qDebug() << "  Refresh rate:" << screen->refreshRate() << "Hz";
        
        // 如果当前屏幕索引大于最高屏幕索引，则更新最高屏幕索引
        if (i > m_highestScreenIndex) {
            m_highestScreenIndex = i;
        }
    }
    
    // 输出最低屏幕索引
    qDebug() << "Lowest screen index:" << m_lowestScreenIndex;
    // 输出最高屏幕索引
    qDebug() << "Highest screen index:" << m_highestScreenIndex;
}

/**
 * @brief 将窗口移动到索引最高的屏幕并全屏显示。
 * 
 * 此函数用于将主窗口移动到所有可用屏幕中索引最高的屏幕，并将窗口设置为全屏显示。
 * 如果没有可用的屏幕，则不进行任何操作。
 */
void MainWindow::moveToHighestIndexScreen()
{
    // 检查是否有可用的屏幕，如果没有则直接返回，不进行移动操作
    if (m_screens.isEmpty()) {
        return;
    }
    
    // 获取索引最高的屏幕对象
    // Get the screen with the highest index
    QScreen *targetScreen = m_screens.at(m_highestScreenIndex);
    
    // 获取目标屏幕的几何信息（位置和大小）
    // Move the window to the target screen
    QRect screenGeometry = targetScreen->geometry();
    // 将窗口移动到目标屏幕的左上角位置
    move(screenGeometry.x(), screenGeometry.y());
    
    // 将窗口设置为全屏显示
    // Go fullscreen
    showFullScreen();
}


/**
 * @brief 初始化用户界面。
 * 
 * 此函数用于设置主窗口的中央部件，在窗口中央加载当前文件夹下的def-logo.png图片，
 * 图片展示宽高为250*200px，在图片下方摆放m_centralLabel，设置m_centralLabel默认内容为“源于教育,服务教育”，
 * 缩小字体为14。
 */
void MainWindow::initializeUI()
{
    // 创建一个垂直布局
    QVBoxLayout *layout = new QVBoxLayout;

    // 创建一个标签用于显示图片，并设置白色、较粗的边框
    QLabel *imageLabel = new QLabel(this);
    imageLabel->setStyleSheet("border: 5px solid white;");

    // 加载图片
    QPixmap pixmap("def-logo.png");
    if (!pixmap.isNull()) {
        // 缩放图片到指定大小
        pixmap = pixmap.scaled(500, 400, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        imageLabel->setPixmap(pixmap);
        imageLabel->setAlignment(Qt::AlignCenter);
        // 将图片标签添加到布局中
        layout->addWidget(imageLabel);
    }

    // 设置中央标签的文本为 "源于教育 服务教育"
    m_centralLabel->setText("源于教育 服务教育");
    m_centralLabel->setStyleSheet("border: 5px solid white;");
    // 设置中央标签的字体大小为 30
    QFont font = m_centralLabel->font();
    font.setPointSize(30);
    m_centralLabel->setFont(font);
    // 设置中央标签的样式表，将文本颜色设置为WHITE
    m_centralLabel->setStyleSheet("color: #FFFFFF;"); // Gray color
    // 将中央标签的文本居中显示
    m_centralLabel->setAlignment(Qt::AlignCenter);

    // 设置 QLabel 的大小策略，使其尽可能扩展
    m_centralLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    // 将中央标签添加到布局中
    layout->addWidget(m_centralLabel, 1); // 权重设为 1，使其占据剩余空间
    // 设置布局在垂直方向上居中对齐
    layout->setAlignment(Qt::AlignVCenter); 
    // 创建一个中央部件
    QWidget *centralWidget = new QWidget(this);
    centralWidget->setStyleSheet("background-color: black;");
    centralWidget->setLayout(layout);
    // 设置主窗口的中央部件
    setCentralWidget(centralWidget);

    // 设置中央标签的属性，使其能够缩放图片并填充整个区域
    m_centralLabel->setScaledContents(true); // 让标签自动缩放图片
    m_centralLabel->setAlignment(Qt::AlignCenter);
}


/**
 * @brief 开始屏幕捕获操作。
 * 
 * 此函数用于启动屏幕捕获定时器，开始周期性地捕获屏幕，并停止启动捕获定时器。
 * 屏幕捕获将以每100毫秒一次的频率进行，以确保流畅的显示效果。
 */
void MainWindow::startScreenCapture()
{
    // 输出调试信息，表明正在开始屏幕捕获操作
    qDebug() << "Starting screen capture...";
    
    // 启动屏幕捕获定时器，开始周期性地捕获屏幕
    // 每100毫秒触发一次，以实现流畅的显示效果
    m_captureTimer->start(100); // Capture every 100ms for smooth display
    // 创建透明度效果对象
    QGraphicsOpacityEffect *opacityEffect = new QGraphicsOpacityEffect(m_centralLabel);
    opacityEffect->setOpacity(0.0); // 初始透明度为完全透明
    m_centralLabel->setGraphicsEffect(opacityEffect);

    // 创建透明度动画对象
    QPropertyAnimation *fadeAnimation = new QPropertyAnimation(opacityEffect, "opacity", this);
    fadeAnimation->setDuration(1000); // 动画时长设置为 1 秒
    fadeAnimation->setStartValue(0.0); // 初始透明度为完全透明
    fadeAnimation->setEndValue(1.0); // 结束时透明度为完全不透明

    // 启动动画，动画结束后自动删除动画对象
    fadeAnimation->start(QAbstractAnimation::DeleteWhenStopped);
    // 动画结束后删除透明度效果对象
    connect(fadeAnimation, &QAbstractAnimation::finished, opacityEffect, &QObject::deleteLater);
    // 停止启动捕获定时器，避免重复触发
    m_startCaptureTimer->stop();
}

/**
 * @brief 捕获屏幕并在界面上显示截图。
 * 
 * 此函数用于定期捕获屏幕，并将捕获的屏幕截图显示在中央标签上。
 * 如果没有可用的屏幕，则不进行任何操作。根据投屏状态，决定捕获哪个屏幕：
 * 如果正在投屏，则捕获正在投屏的屏幕；否则，捕获最低索引的屏幕。
 */
void MainWindow::captureScreen()
{
    // 检查是否有可用的屏幕，如果没有则直接返回，不进行捕获操作
    if (m_screens.isEmpty()) {
        return;
    }
    
    // 确定要捕获的屏幕索引
    // 如果正在进行投屏操作，则使用正在投屏的屏幕索引
    // 否则，使用最低索引的屏幕进行捕获
    int sourceScreenIndex = m_isCasting ? m_castingScreenIndex : m_lowestScreenIndex;
    
    // 根据确定的索引获取要捕获的屏幕对象
    QScreen *sourceScreen = m_screens.at(sourceScreenIndex);
    
    // 捕获指定屏幕的内容，grabWindow(0) 表示捕获整个屏幕
    QPixmap screenshot = sourceScreen->grabWindow(0);

    // 先显示新的截图
    m_centralLabel->setPixmap(screenshot);

    
}

